Iterators
Daha önceki derslerimizde iteratorleri görüntüledik. Ancak şimdi yeniden kısaca bir göz atabiliriz.
let vec = vec![1,2,3]
for val in vec.iter{
println!("{}", val);
}
Yukarıda daha önceden de gördüğümüz bir iteratör örneği verilmiştir. iter
yapısı sayesinde belirli bir liste içerisindeki tüm elamanları bir değişkenlere eşitleyerek işlemler yapabiliriz.
Rust içerisinde bulunan tüm iteratorler Rust ile hazır gelen Iterator
trait'ini kullanmaktadır. Bu yapı şu şekilde gözükmektedir.
pub trait Iterator {
type item;
fn next(&mut self) -> Option<Self::Item>;
}
Bu yapılar içerisinde birçok kavram ile gelmektedir. İçerisinde bulunan next
yapısı bir sonraki gelecek verinin Some
veya None
olmasını sağlamaktadır.
Ayrıca into
yapısına da sahip olmaktayız.
let vec2 = vec![1,2,3];
let mut iter = (&vec2).into_iter();
while let Some(v) = iter.next(){
println!("{}", v);
}
Yukarıda verilen yapıda da gördüğümüz gibi into_iter
yapısını da kullanarak koleksiyonların içerisindeki değerlere erişim sağlayabiliriz.
NOT: Bir
Iterator
,Iterator
Trait
'ini içeren tüm yapılardan oluşmaktadır. BirIterable
yapısı ise içerisine tüminto
yapısını içeren yapılardır.
Hadi öğrendiklerimizi biraz daha açalım. Item adında bir struct yapısı oluşturalım
#[derive(Debug)]
struct Item{
name: String
}
Sonrasında bu itemleri kontrol edecek bir fonksiyon yazabiliriz.
fn check_inventory(items: Vec<Item>, product: String) -> Vec<Item>{
items.into_iter().filter(|i| i.name == product).collect()
}
Yapımızı oluşturduk. Artık içerisine veri eklemeye başlayabiliriz.
let mut vec: Vec<Item> = Vec::new();
vec.push(Item {
name: String::from("coat");
});
vec.push(Item {
name: String::from("shirt");
});
vec.push(Item {
name: String::from("shorts");
});
vec.push(Item {
name: String::from("shoes");
});
Sonrasında artık tanımladığımız fonksiyon ile envanteri kontrol edebiliz.
let cheched = fn check_inventory(vec, String::from("shirt"));
println!("{:?}",checked)
Yukarıda tanımladığımız checked_inventory
yapımıza daha da ayrıntılı baktığımızda into_iter
ile oluşturduğumuz bir iteratörün oluşturduğumuz vektörün sahipliğini aldığını sonrasında filter
ile sadace içerisinde bulunan değerin true olduğu zamanlarda çalışmasını sağladığımız bir yapı vardır. İçerisinde bulunan closure
ise true false değerinin oluşmasını sağlamaktadır. Oluşturduğumuz değerleri sonrasında colect
ile toplarız.
Peki kendi iteratörlerimizi oluşturmak isteseydik bunu nasıl yapabilirdik? Hadi bu duruma yeni bir struct yapısı oluşturarak bakalım.
#[derive(Debug)]
struct Range{
start: u32,
end: u32
}
impl Iterator for Range {
type Item = u32,
fn next(&mut self) -> Option<self::Item> {
if self.start >= self.end {
return None;
}
let result = Some(self.start);
self.start += 1;
result
}
}
Sonrasında yapımızın çalışıp çalışmadığını test etmek için:
let mut range = Range{start: 0, end: 10};
for r in range {
println!("{}", r);
}
Kodumuzu çalıştırdığımızda 0'dan 10'a kadar başarılı bir şekilde yazdırıldığını görüntüleyebiliriz.
Daha önce de öğrendiğimiz üzere next
fonksiyonunu eklediğimize göre bazı ekstra özellikler de almamız gerekmektedir. Bu durumun sağlandığını kontrol etmek için alt kısımda ifade edilen kodu yazabiliriz.
let vec: Vec<u32> = range.filter(|x| x %2 == 0).collect();
println!("{:?}", vec);